<template>
  <div class="interview-AI-wrap" ref="wrap">
    <article v-if="start">
      <h2>面试承诺书</h2>
      <p>我，谨代表自己，在参加您公司的面试过程中，郑重承诺以下事项：</p>
      <p class="paragraph">
        1.<b>诚信守规：</b>我将始终本着诚实、真实的原则，提供真实、准确的个人信息、简历和证明材料。我不会故意夸大或隐瞒自己的能力、经验或资历。
      </p>
      <p class="paragraph">
        2.<b>尊重原则：</b>我将尊重和礼貌地对待面试官和面试团队的所有成员。我将倾听并认真回答面试问题，不会故意散发虚假信息或误导性的答案。
      </p>
      <p class="paragraph">
        3.<b>保密承诺：</b>我将对面试期间接触到的企业敏感信息和商业机密，保持严格的保密，并在合适的时候签署相关的保密协议。我将遵守公司关于保密事项的所有规定。
      </p>
      <p class="paragraph">
        4.<b>尽力而为：</b>我承诺将会全力以赴，充分准备面试，展示出自己的最佳水平和能力。我将积极参与面试过程，并展示出对公司和岗位的兴趣和热情。
      </p>
      <p class="paragraph">
        5.<b>尊重时间：</b>我将准时参加面试，并尽量避免迟到。如果有任何不可预见的情况导致我不能准时参加面试，我会提前通知面试团队，并尽量安排另一个时间。
      </p>
      <p class="paragraph">
        6.<b>尊重决定：</b>我将尊重面试团队的决定，并接受他们根据面试结果做出的决策。我不会对面试团队的决定提出异议或采取任何不恰当的行为。
      </p>
      <p>
        我郑重承诺以上事项，并愿意承担由此产生的责任。如果我违反了上述承诺，我同意接受公司将要采取的合适的纠正措施，这可能包括取消面试资格或终止雇佣关系。
      </p>
      <p>我感谢您给予我参加面试的机会，并期待有机会成为贵公司的一员。谢谢您对我的考虑。</p>
      <p>此致</p>
      <p class="handWritten">
        <b>签名：</b>
        <button class="handWrittenStart" v-if="!writtenEnd" @click="written">开始签名</button>
        <img :src="handWrittenUrl" alt="" v-if="handWrittenUrl" class="showHandWritten" />
      </p>
      <p>{{ new Date().toLocaleDateString() }}</p>
      <div class="agree">
        <input type="checkbox" v-model="agree" id="agree" />
        <label for="agree">我接受以上承诺事项 </label
        ><span class="userAgreement" @click="showAgreement = true">用户协议</span>
        <el-dialog v-model="showAgreement" width="800px" align-center>
          <h3>【用户协议】</h3>
          <p>
            欢迎使用我们的服务！在使用我们的服务之前，请仔细阅读以下用户协议。本协议涵盖您使用我们提供的所有服务，包括但不限于摄像头、音频等设备的调用。
          </p>
          <h3>【服务说明】</h3>
          <p>
            我们的服务可能需要调用您的电脑摄像头、音频设备等硬件设备，以提供更好的用户体验和功能支持。您的设备将仅在您明确同意的情况下调用，并且我们只会在必要时使用这些设备，以满足特定功能或服务的要求。
          </p>
          <h3>【用户隐私】</h3>
          <p>
            我们尊重和保护用户的隐私，我们不会未经允许擅自调用您的设备或收集您的个人信息。您的设备调用操作将受到严格的隐私政策和法律法规的保护，我们承诺不会滥用您的隐私数据。
          </p>
          <h3>【安全性保障】</h3>
          <p>
            我们将采取必要的安全措施，保障您的设备和数据的安全。 -
            在调用您的设备时，我们将尽最大努力确保设备操作的安全性和稳定性，以防止任何可能的安全风险。
          </p>
          <h3>【用户责任】</h3>
          <p>
            您应当妥善保管您的账户信息，不得将账户信息透露给他人。如发现任何异常或未经授权的设备调用行为，请及时联系我们并采取必要的安全措施。通过使用我们的服务，即表示您同意遵守以上用户协议。我们保留随时更新和修改本协议的权利。
          </p>
          <template #footer>
            <div class="dialog-footer">
              <el-button type="primary" @click="showAgreement = false"> 确定 </el-button>
            </div>
          </template>
        </el-dialog>
      </div>
      <button class="submit" @click="startInterview">同意</button>
      <aside v-if="writtenStart">
        <div class="prompt-message">
          在电脑上手写签名时，请使用鼠标或触摸板进行书写，并尽量保持签名清晰和流畅。您可以使用指定的绘图工具或签名软件，在提供的签名区域内完成您的签名。确保您的签名与您的正式签名一致，并在完成后确认保存您的签名以便提交。
        </div>
        <handWrittenSignature @save="save" />
      </aside>
    </article>

    <template v-else-if="isLoading">
      <loading :text="'正在为您准备试卷，请稍后...'" />
    </template>
    <template v-else-if="!isLoading">
      <header>
        <p>{{ questionData.workName }}</p>
      </header>
      <main>
        <ul class="answer-area">
          <li class="timer-wrap">
            <p>
              您将有{{ Math.floor(question.timeInSeconds / 60) }}分{{
                question.timeInSeconds % 60
              }}秒时间作答
            </p>
            <div class="timer">
              剩余时间:<b class="time">{{ formatterTime }}</b>
            </div>
          </li>
          <li class="question">
            <b>试题{{ id + 1 }}：</b>
            <div>
              <p>{{ question.question }}</p>
            </div>
          </li>
          <li class="answer">
            <b>答题区域:</b>
            <div class="speak-btns">
              <button class="speak" @click="startSpeak" ref="speakButton">语音输入</button
              ><button class="cancelSpeak" v-show="isRecognitionRunning" @click="cancelSpeak">
                取消语音识别
              </button>
            </div>
            <textarea class="answer-content" ref="speakInput"></textarea>
            <button @click="submit" class="submit">提交</button>
          </li>
        </ul>
        <ul class="AI-area">
          <li class="AI">
            <img src="/src/assets/icons/ai机器人.gif" alt="面试AI" />
          </li>
          <li class="question-on-going">
            <div class="question-AI">
              <p>
                {{ question.question }}
              </p>
            </div>
          </li>
          <li class="preview-wrap">
            <video id="preview" autoplay></video>
          </li>
        </ul>
      </main>
    </template>
  </div>
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import loading from '@/components/loading/loading.vue'
import axios from 'axios'
import handWrittenSignature from '@/components/handWrittenSignature/handWrittenSignature.vue'
import { speak } from '@/utils/speak'
const router = useRouter()
const questionData = ref(null)
const questionList = ref(null)
const question = ref(null)
const showError = (message: string) => {
  ElMessage.error(message)
}
const showSuccess = (message: string) => {
  ElMessage.success(message)
}
// 签名是否完成
const writtenEnd = ref(false)
// 是否开始签名
const writtenStart = ref(false)
const handWrittenUrl = ref('')
const written = () => {
  writtenStart.value = true
}

const save = (url) => {
  console.log(url)
  handWrittenUrl.value = url
  writtenEnd.value = true
  writtenStart.value = false
}
// loading外层遮罩对象
const wrap = ref(null)
// 面试开始判断条件
//xx
const start = ref(true)
// 是否同意承诺书
const agree = ref(true)
// 展示用户协议
const showAgreement = ref(false)

// 题目时间
const time = ref(0)
// 进度条定时器
const timer1 = ref(null)
const timeout1 = ref(null)
// 倒计时定时器
const timer2 = ref(null)
const timeout2 = ref(null)
// 题目id
const id = ref(-1)
// 语音转文字输出框
const speakInput = ref(null)
// 语音转文字按钮
const speakButton = ref(null)
// 视频音频控制
const mediaRecorder = ref(null)
// 格式化时间
const formatterTime = computed(() => {
  const minutes = Math.floor(time.value / 60)
  const seconds = time.value % 60
  return `${minutes < 10 ? '0' + minutes : minutes}:${seconds < 10 ? '0' + seconds : seconds}`
})

// 加载loading
const isLoading = ref(true)

//获取题目
// 判断是否同意承诺书,
const startInterview = async () => {
  if (agree.value) {
    if (writtenEnd.value) {
      start.value = false

      // questionList.value = [
      //   {
      //     question:
      //       '请您详细描述一下如何使用Vue.js实现组件化开发，并阐述其中的优点和需要注意的问题。',
      //     id: 1,
      //     timeInSeconds: 480
      //   },
      //   {
      //     question:
      //       '请您阐述一下如何在前端项目中实现状态管理，并列举出两种常见的前端状态管理库，分析它们的优缺点。',
      //     id: 2,
      //     timeInSeconds: 420
      //   },
      //   {
      //     question: '请您解释一下前端性能优化的几种常见方式，并举例说明它们的应用场景。',
      //     id: 3,
      //     timeInSeconds: 360
      //   },
      //   {
      //     question: '请您解释一下跨域请求的原理，并列举出三种解决跨域请求的方法。',
      //     id: 4,
      //     timeInSeconds: 420
      //   },
      //   {
      //     question: '请您阐述一下如何在前端项目中实现代码分割，并说明其优点。',
      //     id: 5,
      //     timeInSeconds: 300
      //   },
      //   {
      //     question: '请您解释一下如何使用Node.js实现后端服务，并描述一下Node.js的特点。',
      //     id: 6,
      //     timeInSeconds: 400
      //   },
      //   {
      //     question: '请您描述一下如何使用React Router实现前端路由管理，并说明其优缺点。',
      //     id: 7,
      //     timeInSeconds: 500
      //   },
      //   {
      //     question: '请您阐述一下如何使用Webpack进行前端项目构建，并描述一下Webpack的原理。',
      //     id: 8,
      //     timeInSeconds: 540
      //   }
      // ]
      await axios
        .post(
          'https://open.bigmodel.cn/api/paas/v4/chat/completions',
          {
            model: 'glm-4',
            messages: [
              {
                role: 'user',
                content: '前端工程师'
              }
            ],
            tools: [
              {
                type: 'retrieval',
                retrieval: {
                  knowledge_id: '1814812851358007296',
                  prompt_template:
                    '你要扮演专业的面试官，必须了解各个岗位的面试流程和专业知识。我是应聘者，我会告诉你我将要面试的岗位，你需要针对我面试的岗位对我进行专业的面试。你从{{knowledge}}中抽取8个符合岗位信息问题,岗位信息相识度不能太大,提问方式要各不相同,你要用你的专业知识丰富问题内容,让问题更专业,返回json数据形式对象数组,其中对象属性有question,id(从1开始自增),timeInSeconds(答题时间,秒,数值在300-600之间)'
                }
              }
            ]
          },
          {
            headers: {
              Authorization:
              'eyJhbGciOiJIUzI1NiIsInNpZ25fdHlwZSI6IlNJR04ifQ.eyJhcGlfa2V5IjoiMGMyOThjYmEzYTMyMmZjMTEwNmQ4MzA4M2MwYTlkNDIiLCJleHAiOjE3MjQxOTgyMDkzNDksInRpbWVzdGFtcCI6MTcyMTUxOTgwOTM0OH0.PdtjS07SG14RpkFupRUDdNUBWvgBx4VcSyJEutQ3BZE',
              'Content-Type': 'application/json'
            }
          }
        )
        .then((res) => {
          let data = res.data.choices[0].message.content.replace('```json', '').replace('```', '')
          console.log(data)
          console.log('dataJSON', JSON.parse(data))
          questionList.value = JSON.parse(data)
          console.log(questionList.value)
        })
        .catch((err) => {
          console.log(err)
        })
        .finally(() => {
          isLoading.value = false
          console.log('start', start.value)
        })
    } else {
      showError('请先签名!')
    }
  } else {
    showError('请先同意承诺书!')
  }
}

// 刷新题目时间
const timer2Func = () => {
  timeout2.value = setTimeout(() => {
    time.value -= 1
    if (time.value > 0) {
      timer2.value = requestAnimationFrame(timer2Func)
    } else {
      cancelAnimationFrame(timer2.value)
    }
  }, 1000)
}

// 实现文字转语音
// const synth = window.speechSynthesis
// const speak = (text: string) => {
//   const utterThis = new SpeechSynthesisUtterance(text)
//   synth.speak(utterThis)
// }

// 实现语音转文字
const isRecognitionRunning = ref(false) //状态变量，用于判断语音识别是否正在运行
const recognition = new webkitSpeechRecognition()
recognition.lang = 'zh-CN'
recognition.continuous = true
recognition.interimResults = true
recognition.onresult = (event) => {
  const result = event.results[event.results.length - 1]
  if (result.isFinal) {
    console.log(12)
    let str = result[0].transcript
    console.log(speakInput.value.value, str)
    // 拼接语音转文字结果
    speakInput.value.value += str
  }
}

// 语音识别结束时，更新状态变量
recognition.onend = () => {
  console.log(456)
  isRecognitionRunning.value = false
  speakButton.value.classList.remove('disable-select')
  speakButton.value.innerText = '语音输入'
}

// 语音识别开始时，更新状态变量
recognition.onstart = () => {
  isRecognitionRunning.value = true // 当 recognition 开始时，更新状态变量
}

// 语音识别错误处理
recognition.onerror = (event) => {
  console.error('Speech recognition error:', event.error)
}

// 开启语音识别
const startSpeak = () => {
  if (!isRecognitionRunning.value) {
    recognition.start()
  }
  if (speakButton.value.classList.contains('disable-select')) {
    return
  }
  speakButton.value.classList.add('disable-select')
  speakButton.value.innerText = '正在识别...'
}

// 取消语音识别
const cancelSpeak = () => {
  recognition.stop()
}

// 更新题目
const freshQuestion = () => {
  id.value += 1
  console.log(1, questionList.value[id.value])
  question.value = questionList.value[id.value]
  time.value = parseInt(question.value.timeInSeconds)
  // progressValue.value = 0
  // timer1Func()

  setTimeout(() => {
    speak(
      `请回答问题${question.value.id}` +
        question.value.question +
        `?` +
        `您将有${Math.floor(question.value.timeInSeconds / 60)}分${question.value.timeInSeconds % 60}秒时间作答`
    )
    timer2Func()
  }, 3000)
}

// 页面跳转判断，是否携带数据
if (history.state.questionData) {
  questionData.value = JSON.parse(history.state.questionData)
} else {
  showError('数据出错啦,请重试!')
  router.push('/geek/interview/aiInterview')
}

// 实现本地摄像头实现录像
const startRecord = () => {
  navigator.mediaDevices
    .getUserMedia({
      video: true,
      audio: true
    })
    .then((stream) => {
      // 创建一个只包含视频轨道的 MediaRecorder 对象
      mediaRecorder.value = new MediaRecorder(stream)

      const chunks = []
      mediaRecorder.value.ondataavailable = (e) => {
        chunks.push(e.data)
      }
      mediaRecorder.value.onstop = (e) => {
        const blob = new Blob(chunks, { type: 'video/mp4' })
        const url = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = 'interview.mp4'
        a.click()
        URL.revokeObjectURL(url)
      }
      // 将媒体流转换为 URL，并设置为 <video> 元素的 src 属性
      const video = document.getElementById('preview')
      video.srcObject = stream
      // 将视频静音
      video.muted = true
      mediaRecorder.value.start()
    })
}

// 销毁时清楚定时器,清除视频录制,清除语音识别,清除文字转语音
onUnmounted(() => {
  console.log('销毁')
  if (timer1.value) {
    cancelAnimationFrame(timer1.value)
  }
  if (timer2.value) {
    cancelAnimationFrame(timer2.value)
  }
  if (timeout1.value) {
    clearTimeout(timeout1.value)
  }
  if (timeout2.value) {
    clearTimeout(timeout2.value)
  }
  if (mediaRecorder.value) {
    console.log()
    mediaRecorder.value.stop()
    mediaRecorder.value.stream.getTracks().forEach((track) => {
      track.stop()
    })
  }
  recognition.stop()
})

const answerList = ref([])

//提交答案
const submit = () => {
  // synth.cancel()
  cancelSpeak()
  if (speakInput.value.value === '') {
    showError('答案不能为空!')
    speak('答案不能为空,请重新输入')
    return
  }
  const answer = speakInput.value.value
  const data = {
    questionId: question.value.id,
    question: question.value.question,
    answer: answer
  }
  answerList.value.push(data)
  speakInput.value.value = ''
  setTimeout(() => {
    showSuccess('提交成功!')
    speak('提交成功,请继续下一题')
    if (timer1.value) {
      cancelAnimationFrame(timer1.value)
    }
    if (timer2.value) {
      cancelAnimationFrame(timer2.value)
    }
    if (timeout1.value) {
      clearTimeout(timeout1.value)
    }
    if (timeout2.value) {
      clearTimeout(timeout2.value)
    }
    freshQuestion()
  }, 1000)
}

// 监控时间,id变化
watch(time, (newTime) => {
  if (newTime === 0) {
    console.log('时间到')
    freshQuestion()
  }
  if (newTime === 60) {
    showSuccess('还有1分钟时间')
    speak('您还有1分钟时间')
  }
})

watch(id, (newId) => {
  if (newId === questionList.value.length) {
    console.log('xxxxxxxxxxx')
    showSuccess('题目已答完,请等待结果!')
    setTimeout(() => {
      mediaRecorder.value.stop()
      mediaRecorder.value.stream.getTracks().forEach((track) => {
        track.stop()
      })
      router.push({
        path: '/interviewResult',
        state: {
          answerList: JSON.stringify(answerList.value)
        }
      })
    }, 2000)
  }
})

// 监视视频录制,监视语音播放

watch(isLoading, (newIsLoading) => {
  if (!newIsLoading) {
    setTimeout(() => {
      startRecord()
      freshQuestion()
    }, 1000)
  }
})
</script>

<style scoped>
.interview-AI-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 1184px;
  height: var(--windowHeight);
  margin: 0 auto;
  background-color: var(--childThemeColor);
  overflow-y: auto;
  overflow-x: hidden;
}

.interview-AI-wrap::after {
  content: '';
  display: block;
  position: absolute;
  inset: 0;
  background: var(--childThemeColor);
  z-index: -1;
}

.interview-AI-wrap article {
  display: flex;
  position: relative;
  flex-direction: column;
  width: 700px;
  padding: 20px;
  box-sizing: border-box;
  margin: auto;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
  background-color: #fff;
}

.interview-AI-wrap article h2 {
  text-align: center;
  font-size: 24px;
  font-weight: bold;
}

.interview-AI-wrap article p {
  margin: 10px 0;
  font-size: var(--font-16);
}

.interview-AI-wrap article p.paragraph {
  text-indent: 2em;
  padding: 0 2em;
  margin-bottom: 10px;
}

#agree {
  margin-right: 10px;
}

.submit {
  border: none;
  padding: 6px 12px;
  width: fit-content;
  border-radius: 4px;
  background: var(--btnBgColor);
  color: #ffffff;
  font-size: var(--font-16);
  cursor: pointer;
  margin: 0 auto;
}

.submit:hover {
  background: var(--btnHoverBgColor);
}

aside {
  display: flex;
  position: absolute;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  width: 100%;
  inset: 0;
  background: white;
  border: 1px solid #ccc;
  box-shadow: var(--boxShadow);
}
.handWritten {
  display: flex;
  justify-content: start;
  align-items: center;
}

.showHandWritten {
  width: 100px;
  height: 50px;
  border: 1px solid #ccc;
  margin-left: 10px;
  margin-right: 10px;
}

.handWrittenStart {
  border: none;
  padding: 6px 12px;
  width: fit-content;
  border-radius: 4px;
  background: var(--btnBgColor);
  color: #ffffff;
  font-size: var(--font-16);
  cursor: pointer;
}

.handWrittenStart:hover {
  background: var(--btnHoverBgColor);
}

.prompt-message {
  width: 80%;
  padding: 10px;
  margin-top: 10px;
}

.userAgreement {
  color: var(--themeColor);
  cursor: pointer;
  text-decoration: underline;
}

.userAgreement:hover {
  color: var(--themeHoverColor);
}

header {
  width: 100%;
  height: 10%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  font-weight: bold;
  background-color: #fff;
}

main {
  display: flex;
  justify-content: space-around;
  overflow-y: auto;
  font-size: var(--font-16);
  width: 100%;
  height: 75vh;
  background-color: #fff;
}

.answer-area {
  width: 50%;
  height: 100%;
  display: flex;
  box-sizing: border-box;
  flex-direction: column;
  justify-content: space-between;
  padding: 20px;
  border-right: 1px solid #ccc;
}

.answer {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  box-sizing: border-box;
  padding: 20px;
}

.answer-content {
  width: 100%;
  font: inherit;
  flex: 1;
  box-sizing: border-box;
  padding: 10px;
  margin: 10px 0;
  border: 1px solid #ccc;
  border-radius: 6px;
  resize: none;
}

.timer-wrap {
  display: flex;
  justify-content: space-between;
}

.timer {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 20px;
  font-weight: bold;
}

.timer .time {
  margin-left: 10px;
  width: 100px;
  height: 24px;
  text-align: center;
  background-color: #e3e6e3;
  border-radius: 6px;
}

.question {
  box-sizing: border-box;
  height: fit-content;
  /* width: 100%; */
  padding: 20px;
}

.question div {
  margin: 10px 0;
  padding: 0 10px;
  /* width: 100%; */
  max-height: 100px;
  overflow-y: scroll;
  background: #f0f0f0;
  border-radius: 6px;
  line-height: 32px;
}

.question p {
  white-space: wrap;
  overflow: hidden;
  height: fit-content;
  /* word-wrap: break-word; */
  /* max-width: 100%; */
  animation: typing 3s steps(60, end);
}

.AI-area {
  width: 50%;
  box-sizing: border-box;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 20px;
}

.AI-area .AI {
  display: flex;
  justify-content: center;
  align-self: center;
  box-sizing: border-box;
  padding: 50px;
  width: fit-content;
}

.AI-area img {
  width: 300px;
  height: 300px;
  border: #fff 2px solid;
  padding: 2px;
}

.question-AI {
  width: fit-content;
}

.question-AI P {
  white-space: wrap;
  overflow: hidden;
  width: 100%;
  animation: typing 3s steps(60, end);
}

.question-on-going {
  display: flex;
  flex: 1;
  width: 100%;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  padding: 20px;
}

.preview-wrap {
  display: flex;
}

.preview-wrap video {
  margin-left: auto;
  width: 150px;
  border: 2px solid #0f0f0f;
}
@keyframes typing {
  from {
    width: 0;
  }
}

.speak-btns {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}

.speak {
  border: none;
  padding: 6px 12px;
  width: fit-content;
  border-radius: 4px;
  background: var(--btnBgColor);
  color: #ffffff;
  font-size: var(--font-16);
  cursor: pointer;
  margin: 0 auto;
  margin-top: 10px;
  margin-bottom: 10px;
}
.speak:hover {
  background: var(--btnHoverBgColor);
}

/* .speak不可被选中 */
.speak.disable-select {
  pointer-events: none;
  background-color: #ccc;
  cursor: not-allowed;
}

.cancelSpeak {
  border: none;
  padding: 6px 12px;
  width: fit-content;
  border-radius: 4px;
  background: var(--btnBgColor);
  color: #ffffff;
  font-size: var(--font-16);
  cursor: pointer;
  margin: 0 auto;
  margin-top: 10px;
  margin-bottom: 10px;
}
.cancelSpeak:hover {
  background: var(--btnHoverBgColor);
}
</style>
